﻿using GoogleMapsHelpers;
using System;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace GoogleMapsHelpers.Builders
{
    public class GoogleMapsScriptBuilder
    {
        #region private variables

        /// <summary>
        /// Tag builder that is used to build googles maps API script tag
        /// </summary>
        private readonly TagBuilder _apiScriptTagBuilder;
        /// <summary>
        /// Tag builder that is used to build google maps options script tag
        /// </summary>
        private readonly TagBuilder _mapScriptTagBuilder;
        /// <summary>
        /// string builder for google maps API source
        /// </summary>
        private readonly StringBuilder _apiSourceBuilder;
        /// <summary>
        /// string builder for google maps initialization script
        /// </summary>
        private readonly StringBuilder _mapInitScriptBuilder;

        #endregion

        #region constructors

        public GoogleMapsScriptBuilder()
        {
            _apiScriptTagBuilder = new TagBuilder(ScriptConstants.Script);
            _apiScriptTagBuilder.MergeAttribute(ScriptConstants.Type, ScriptConstants.TextJavaScript);

            _mapScriptTagBuilder = new TagBuilder(ScriptConstants.Script);
            _mapScriptTagBuilder.MergeAttribute(ScriptConstants.Type, ScriptConstants.TextJavaScript);

            _apiSourceBuilder = new StringBuilder();
            _apiSourceBuilder.Append(ScriptConstants.ApiSource);

            _mapInitScriptBuilder = new StringBuilder();
            _mapInitScriptBuilder.Append(
                "var m;" +
                "var g;" +
                "function i(){" +
                    "g=new google.maps.Geocoder();"
            );
        }

        #endregion

        #region API build methods

        /// <summary>
        /// Adds Google Maps API key to the API source link
        /// </summary>
        /// <param name="key"></param>
        public void AddApiKey(string key)
        {
            _apiSourceBuilder.Append(ScriptConstants.ApiKey + key + ScriptConstants.Amp);
        }

        /// <summary>
        /// Adds sensor option to the API source link
        /// </summary>
        /// <param name="sensorOption"></param>
        public void AddSensorOption(bool sensorOption)
        {
            _apiSourceBuilder.Append(ScriptConstants.SensorKey + sensorOption.ToString().ToLower());
        }

        #endregion

        #region map options build method

        /// <summary>
        /// Add map options to the Initialization script
        /// </summary>
        /// <param name="zoom"></param>
        /// <param name="mapType"></param>
        public void AddMapOtiopn(int? zoom, MapTypes? mapType)
        {
            _mapInitScriptBuilder.Append(
                    "var o={");
            if (zoom.HasValue)
                _mapInitScriptBuilder.Append(
                        "zoom:").Append(zoom.Value).Append(",");
            else
                _mapInitScriptBuilder.Append(
                        "zoom:8,");

            if (mapType == null)
                _mapInitScriptBuilder.Append(
                        "mapTypeId:google.maps.MapTypeId.ROADMAP");
            else
                _mapInitScriptBuilder.Append(
                        "mapTypeId:google.maps.MapTypeId.").Append(mapType.ToString().ToUpper());

            _mapInitScriptBuilder.Append(
                    "};").Append(
                    "m=new google.maps.Map(document.getElementById('map-canvas'),o);");
        }

        public void AddMarkers(string address)
        {
            _mapInitScriptBuilder.Append(
                    "g.geocode({'address':'").Append(address).Append("'},function(r,s){").Append(
                        "if(s==google.maps.GeocoderStatus.OK){").Append(
                            "m.setCenter(r[0].geometry.location);");
            _mapInitScriptBuilder.Append(
                            "var k=new google.maps.Marker({");
            _mapInitScriptBuilder.Append(
                                "map:m,");
            _mapInitScriptBuilder.Append(
                                "position: r[0].geometry.location");
            _mapInitScriptBuilder.Append(
                            "});");
            _mapInitScriptBuilder.Append(
                        "}").Append(
                    "});");
        }

        public void AddMarkers(string[] addresses)
        {
            for (int i = 0; i < addresses.Length; i++)
            {
                _mapInitScriptBuilder.Append(
                        "var b=new google.maps.LatLngBounds();");
                _mapInitScriptBuilder.Append(
                        "g.geocode({'address':'").Append(addresses[i]).Append("'},function(r,s){").Append(
                            "if(s==google.maps.GeocoderStatus.OK){").Append(
                                "m.setCenter(r[0].geometry.location);");
                _mapInitScriptBuilder.Append(
                                "var k").Append(i).Append("=new google.maps.Marker({");
                _mapInitScriptBuilder.Append(
                                    "map:m,");
                _mapInitScriptBuilder.Append(
                                    "position: r[0].geometry.location");
                _mapInitScriptBuilder.Append(
                                "});");
                _mapInitScriptBuilder.Append(
                                "b.extend(r[0].geometry.location)");
                _mapInitScriptBuilder.Append(
                            "}").Append(
                        "});");
            }

            _mapInitScriptBuilder.Append(
                    "m.fitBounds(b);");
        }

        #endregion

        /// <summary>
        /// Get completed API scritp and map options script
        /// </summary>
        /// <returns></returns>
        public IHtmlString GetResult()
        {
            _apiScriptTagBuilder.MergeAttribute(ScriptConstants.Source, this._apiSourceBuilder.ToString());

            _mapInitScriptBuilder.Append(
                "}google.maps.event.addDomListener(window, 'load', i);");
            _mapScriptTagBuilder.SetInnerText(this._mapInitScriptBuilder.ToString());

            return new HtmlString(HttpUtility.HtmlDecode(this._apiScriptTagBuilder.ToString(TagRenderMode.Normal) + this._mapScriptTagBuilder.ToString(TagRenderMode.Normal)));
        }
    }
}
